<!DOCTYPE html>
<meta charset=utf-8>
<title>Transformed progress</title>
<link rel="help" href="https://drafts.csswg.org/web-animations/#calculating-the-transformed-progress">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="../../testcommon.js"></script>
<script src="../../resources/easing-tests.js"></script>
<body>
<div id="log"></div>
<div id="target"></div>
<script>
'use strict';

for (const params of gEasingTests) {
  test(t => {
    const target = createDiv(t);
    const anim   = target.animate(null, { duration: 1000,
                                          fill: 'forwards',
                                          easing: params.easing });

    for (const sampleTime of [0, 250, 500, 750, 1000]) {
      anim.currentTime = sampleTime;
      const portion = sampleTime / anim.effect.getComputedTiming().duration;
      const expectedProgress = params.easingFunction(portion);
      assert_approx_equals(anim.effect.getComputedTiming().progress,
                           expectedProgress,
                           0.01,
                           'The progress should be approximately ' +
                           `${expectedProgress} at ${sampleTime}ms`);
    }
  }, `Transformed progress for ${params.desc}`);
}

// Additional tests for various boundary conditions of step timing functions.

const gStepTimingFunctionTests = [
  {
    description: 'Test bounds point of step-start easing',
    effect:     {
                  delay: 1000,
                  duration: 1000,
                  fill: 'both',
                  easing: 'steps(2, start)'
                },
    conditions: [
                  { currentTime: 0,    progress: 0 },
                  { currentTime: 999,  progress: 0 },
                  { currentTime: 1000, progress: 0.5 },
                  { currentTime: 1499, progress: 0.5 },
                  { currentTime: 1500, progress: 1 },
                  { currentTime: 2000, progress: 1 }
                ]
  },
  {
    description: 'Test start bounds of step-start easing with no delay',
    effect:     {
                  delay: 0,
                  duration: 1000,
                  fill: 'backwards',
                  easing: 'steps(1, start)'
                },
    conditions: [
                  { currentTime: -1, progress: 0 },
                  { currentTime:  0, progress: 1 }
                ]
  },
  {
    description: 'Test bounds point of step-start easing with reverse direction',
    effect:     {
                  delay: 1000,
                  duration: 1000,
                  fill: 'both',
                  direction: 'reverse',
                  easing: 'steps(2, start)'
                },
    conditions: [
                  { currentTime: 0,    progress: 1 },
                  { currentTime: 1001, progress: 1 },
                  { currentTime: 1500, progress: 1 },
                  { currentTime: 1501, progress: 0.5 },
                  { currentTime: 2000, progress: 0 },
                  { currentTime: 2500, progress: 0 }
                ]
  },
  {
    description: 'Test bounds point of step-start easing ' +
                 'with iterationStart not at a transition point',
    effect:     {
                  delay: 1000,
                  duration: 1000,
                  fill: 'both',
                  iterationStart: 0.25,
                  easing: 'steps(2, start)'
                },
    conditions: [
                  { currentTime: 0,    progress: 0.5 },
                  { currentTime: 999,  progress: 0.5 },
                  { currentTime: 1000, progress: 0.5 },
                  { currentTime: 1249, progress: 0.5 },
                  { currentTime: 1250, progress: 1 },
                  { currentTime: 1749, progress: 1 },
                  { currentTime: 1750, progress: 0.5 },
                  { currentTime: 2000, progress: 0.5 },
                  { currentTime: 2500, progress: 0.5 },
                ]
  },
  {
    description: 'Test bounds point of step-start easing ' +
                 'with iterationStart and delay',
    effect:     {
                  delay: 1000,
                  duration: 1000,
                  fill: 'both',
                  iterationStart: 0.5,
                  easing: 'steps(2, start)'
                },
    conditions: [
                  { currentTime: 0,    progress: 0.5 },
                  { currentTime: 999,  progress: 0.5 },
                  { currentTime: 1000, progress: 1 },
                  { currentTime: 1499, progress: 1 },
                  { currentTime: 1500, progress: 0.5 },
                  { currentTime: 2000, progress: 1 }
                ]
  },
  {
    description: 'Test bounds point of step-start easing ' +
                 'with iterationStart and reverse direction',
    effect:     {
                  delay: 1000,
                  duration: 1000,
                  fill: 'both',
                  iterationStart: 0.5,
                  direction: 'reverse',
                  easing: 'steps(2, start)'
                },
    conditions: [
                  { currentTime: 0,    progress: 1 },
                  { currentTime: 1000, progress: 1 },
                  { currentTime: 1001, progress: 0.5 },
                  { currentTime: 1499, progress: 0.5 },
                  { currentTime: 1500, progress: 1 },
                  { currentTime: 1999, progress: 1 },
                  { currentTime: 2000, progress: 0.5 },
                  { currentTime: 2500, progress: 0.5 }
                ]
  },
  {
    description: 'Test bounds point of step(4, start) easing ' +
                 'with iterationStart 0.75 and delay',
    effect:     {
                  duration: 1000,
                  fill: 'both',
                  delay: 1000,
                  iterationStart: 0.75,
                  easing: 'steps(4, start)'
                },
    conditions: [
                  { currentTime: 0,    progress: 0.75 },
                  { currentTime: 999,  progress: 0.75 },
                  { currentTime: 1000, progress: 1 },
                  { currentTime: 2000, progress: 1 },
                  { currentTime: 2500, progress: 1 }
                ]
  },
  {
    description: 'Test bounds point of step-start easing ' +
                 'with alternate direction',
    effect:     {
                  duration: 1000,
                  fill: 'both',
                  delay: 1000,
                  iterations: 2,
                  iterationStart: 1.5,
                  direction: 'alternate',
                  easing: 'steps(2, start)'
                },
    conditions: [
                  { currentTime: 0,    progress: 1 },
                  { currentTime: 1000, progress: 1 },
                  { currentTime: 1001, progress: 0.5 },
                  { currentTime: 2999, progress: 1 },
                  { currentTime: 3000, progress: 0.5 },
                  { currentTime: 3500, progress: 0.5 }
                ]
  },
  {
    description: 'Test bounds point of step-start easing ' +
                 'with alternate-reverse direction',
    effect:     {
                  duration: 1000,
                  fill: 'both',
                  delay: 1000,
                  iterations: 2,
                  iterationStart: 0.5,
                  direction: 'alternate-reverse',
                  easing: 'steps(2, start)'
                },
    conditions: [
                  { currentTime: 0,    progress: 1 },
                  { currentTime: 1000, progress: 1 },
                  { currentTime: 1001, progress: 0.5 },
                  { currentTime: 2999, progress: 1 },
                  { currentTime: 3000, progress: 0.5 },
                  { currentTime: 3500, progress: 0.5 }
                ]
  },
  {
    description: 'Test bounds point of step-end easing',
    effect:     {
                  delay: 1000,
                  duration: 1000,
                  fill: 'both',
                  easing: 'steps(2, end)'
                },
    conditions: [
                  { currentTime: 0,    progress: 0 },
                  { currentTime: 999,  progress: 0 },
                  { currentTime: 1000, progress: 0 },
                  { currentTime: 1499, progress: 0 },
                  { currentTime: 1500, progress: 0.5 },
                  { currentTime: 2000, progress: 1 }
                ]
  },
  {
    description: 'Test bounds point of step-end easing ' +
                 'with iterationStart and delay',
    effect:     {
                  duration: 1000,
                  fill: 'both',
                  delay: 1000,
                  iterationStart: 0.5,
                  easing: 'steps(2, end)'
                },
    conditions: [
                  { currentTime: 0,    progress: 0 },
                  { currentTime: 999,  progress: 0 },
                  { currentTime: 1000, progress: 0.5 },
                  { currentTime: 1499, progress: 0.5 },
                  { currentTime: 1500, progress: 0 },
                  { currentTime: 1999, progress: 0 },
                  { currentTime: 2000, progress: 0.5 },
                  { currentTime: 2500, progress: 0.5 }
                ]
  },
  {
    description: 'Test bounds point of step-end easing ' +
                 'with iterationStart not at a transition point',
    effect:     {
                  delay: 1000,
                  duration: 1000,
                  fill: 'both',
                  iterationStart: 0.75,
                  easing: 'steps(2, end)'
                },
    conditions: [
                  { currentTime: 0,    progress: 0.5 },
                  { currentTime: 999,  progress: 0.5 },
                  { currentTime: 1000, progress: 0.5 },
                  { currentTime: 1249, progress: 0.5 },
                  { currentTime: 1250, progress: 0 },
                  { currentTime: 1749, progress: 0 },
                  { currentTime: 1750, progress: 0.5 },
                  { currentTime: 2000, progress: 0.5 },
                  { currentTime: 2500, progress: 0.5 },
                ]
  },
  {
    description: 'Test bounds point of steps(jump-both) easing',
    effect:     {
                  delay: 1000,
                  duration: 1000,
                  fill: 'both',
                  easing: 'steps(2, jump-both)'
                },
    conditions: [
                  { currentTime: 0,    progress: 0 },
                  { currentTime: 999,  progress: 0 },
                  { currentTime: 1000, progress: 1/3 },
                  { currentTime: 1499, progress: 1/3 },
                  { currentTime: 1500, progress: 2/3 },
                  { currentTime: 2000, progress: 1 }
                ]
  },
  {
    description: 'Test bounds point of steps(jump-both) easing ' +
                 'with iterationStart and delay',
    effect:     {
                  duration: 1000,
                  fill: 'both',
                  delay: 1000,
                  iterationStart: 0.5,
                  easing: 'steps(2, jump-both)'
                },
    conditions: [
                  { currentTime: 0,    progress: 1/3 },
                  { currentTime: 999,  progress: 1/3 },
                  { currentTime: 1000, progress: 2/3 },
                  { currentTime: 1499, progress: 2/3 },
                  { currentTime: 1500, progress: 1/3 },
                  { currentTime: 1999, progress: 1/3 },
                  { currentTime: 2000, progress: 2/3 },
                  { currentTime: 2500, progress: 2/3 }
                ]
  },
  {
    description: 'Test bounds point of steps(jump-both) easing ' +
                 'with iterationStart not at a transition point',
    effect:     {
                  delay: 1000,
                  duration: 1000,
                  fill: 'both',
                  iterationStart: 0.75,
                  easing: 'steps(2, jump-both)'
                },
    conditions: [
                  { currentTime: 0,    progress: 2/3 },
                  { currentTime: 999,  progress: 2/3 },
                  { currentTime: 1000, progress: 2/3 },
                  { currentTime: 1249, progress: 2/3 },
                  { currentTime: 1250, progress: 1/3 },
                  { currentTime: 1749, progress: 1/3 },
                  { currentTime: 1750, progress: 2/3 },
                  { currentTime: 2000, progress: 2/3 },
                  { currentTime: 2500, progress: 2/3 }
                ]
  },
  {
    description: 'Test bounds point of steps(jump-none) easing',
    effect:     {
                  delay: 1000,
                  duration: 1000,
                  fill: 'both',
                  easing: 'steps(2, jump-none)'
                },
    conditions: [
                  { currentTime: 0,    progress: 0 },
                  { currentTime: 1000, progress: 0 },
                  { currentTime: 1499, progress: 0 },
                  { currentTime: 1500, progress: 1 },
                  { currentTime: 2000, progress: 1 }
                ]
  },
  {
    description: 'Test bounds point of steps(jump-none) easing ' +
                 'with iterationStart and delay',
    effect:     {
                  duration: 1000,
                  fill: 'both',
                  delay: 1000,
                  iterationStart: 0.5,
                  easing: 'steps(2, jump-none)'
                },
    conditions: [
                  { currentTime: 0,    progress: 0 },
                  { currentTime: 999,  progress: 0 },
                  { currentTime: 1000, progress: 1 },
                  { currentTime: 1499, progress: 1 },
                  { currentTime: 1500, progress: 0 },
                  { currentTime: 1999, progress: 0 },
                  { currentTime: 2000, progress: 1 },
                  { currentTime: 2500, progress: 1 }
                ]
  },
  {
    description: 'Test bounds point of steps(jump-none) easing ' +
                 'with iterationStart not at a transition point',
    effect:     {
                  delay: 1000,
                  duration: 1000,
                  fill: 'both',
                  iterationStart: 0.75,
                  easing: 'steps(2, jump-none)'
                },
    conditions: [
                  { currentTime: 0,    progress: 1 },
                  { currentTime: 999,  progress: 1 },
                  { currentTime: 1000, progress: 1 },
                  { currentTime: 1249, progress: 1 },
                  { currentTime: 1250, progress: 0 },
                  { currentTime: 1749, progress: 0 },
                  { currentTime: 1750, progress: 1 },
                  { currentTime: 2000, progress: 1 },
                  { currentTime: 2500, progress: 1 }
                ]
  },
];

for (const options of gStepTimingFunctionTests) {
  test(t => {
    const target = createDiv(t);
    const animation = target.animate(null, options.effect);
    for (const condition of options.conditions) {
      animation.currentTime = condition.currentTime;
      assert_equals(animation.effect.getComputedTiming().progress,
                    condition.progress,
                    `Progress at ${animation.currentTime}ms`);
    }
  }, options.description);
}

test(t => {
  const target = createDiv(t);
  const anim = target.animate(
      [
        { easing: 'steps(1, start)', opacity: 0 },
        { opacity: 1 }
      ],
      { easing: 'linear(-2, 2)', duration: 1000, fill: 'both' });

  anim.currentTime = 0;
  assert_equals(anim.effect.getComputedTiming().progress, -2);
  // Input < 0 ==> output = 0.
  assert_equals(getComputedStyle(target).opacity, "0");
  anim.currentTime = 500;
  assert_equals(anim.effect.getComputedTiming().progress, 0);
  // Input = 0 & before flag = false ==> output = 1.
  assert_equals(getComputedStyle(target).opacity, "1");
  anim.currentTime = 1000;
  // Input > 0 & before flag = false ==> output = 1.
  assert_equals(anim.effect.getComputedTiming().progress, 2);
  assert_equals(getComputedStyle(target).opacity, "1");

}, 'Test global timing function with values outside [0,1] with a step ' +
   'timing function on the keyframe');

</script>
</body>
